﻿using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.ApplicationServices;
using System.Collections.Generic;
using GeoFits;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;

namespace GeoFitsACAD
{
    public class ACADEntrance
    {
        [CommandMethod("CirFit")]
        public void CircleFit()
        {
            //do something in AutoCAD
            Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
            Database db = HostApplicationServices.WorkingDatabase;
            
            List<Point3d> ptList = new List<Point3d>();
            PromptSelectionOptions selectOption = new PromptSelectionOptions();
            selectOption.SingleOnly = false;
            selectOption.AllowDuplicates = false;

            selectOption.MessageForAdding = "选择圆拟合用点";
            selectOption.AllowSubSelections = false;
            TypedValue[] filList = new TypedValue[]{
                    new TypedValue((int)DxfCode.Operator, "<OR"),
                    new TypedValue((int)DxfCode.Start,"POINT"),
                    new TypedValue((int)DxfCode.Start, "TEXT"),
                    new TypedValue((int)DxfCode.Start, "INSERT"),
                    new TypedValue((int)DxfCode.Operator, "OR>")
                };
            SelectionFilter filter = new SelectionFilter(filList);
            PromptSelectionResult psr = ed.GetSelection(selectOption, filter);
            if (psr.Status != PromptStatus.OK || psr.Value.Count == 0)
            {
                ed.WriteMessage("未选择足够的点进行拟合！\r\n");
                return;
            }

            using (Transaction trans = db.TransactionManager.StartTransaction())
            {
                foreach (ObjectId objId in psr.Value.GetObjectIds())
                {
                    DBObject ent = trans.GetObject(objId, OpenMode.ForRead);
                    if (ent.GetType() == typeof(DBPoint))
                    {
                        ptList.Add(((DBPoint)ent).Position);
                    }                    
                }
            }

            if (ptList.Count < 3)
            {
                ed.WriteMessage("未选择足够的点进行拟合！\r\n");
                return;
            }
            List<Point> ptlist2 = AcadPt2Pt(ptList);
            var ftResult = GeoFits.CircleFit.Fit2D(ptlist2);
            GeoFits.Circle c1 = ftResult.ResultGeometry as GeoFits.Circle;
            ed.WriteMessage("圆心坐标为：" + c1.Center.X.ToString("F4") + "," + c1.Center.Y.ToString("F4") + "," + c1.Center.Z.ToString("F4"));
            ed.WriteMessage("半径为：" + c1.Radius.ToString("F4") + "\r\n");

            ftResult = GeoFits.CircleFit.Fit2D(ptlist2, null, 0, new RLSConfig());
            GeoFits.Circle c2 = ftResult.ResultGeometry as GeoFits.Circle;
            ed.WriteMessage("抗差圆心坐标为：" + c2.Center.X.ToString("F4") + "," + c2.Center.Y.ToString("F4") + "," + c2.Center.Z.ToString("F4"));
            ed.WriteMessage("半径为：" + c2.Radius.ToString("F4") + "\r\n");

            RLSConfig config = new RLSConfig();
            config.getWeight = Adjustment.getWeightL1;
            ftResult = GeoFits.CircleFit.Fit2D(ptlist2, null, 0, config);
            GeoFits.Circle c3 = ftResult.ResultGeometry as GeoFits.Circle;
            ed.WriteMessage("L1抗差圆心坐标为：" + c3.Center.X.ToString("F4") + "," + c3.Center.Y.ToString("F4") + "," + c3.Center.Z.ToString("F4"));
            ed.WriteMessage("半径为：" + c3.Radius.ToString("F4") + "\r\n");
            //ed.WriteMessage("Hello AutoCAD");
        }

        private List<Point> AcadPt2Pt(List<Point3d> ptList)
        {
            List<Point> retList = new List<Point>();
            foreach(var pt in ptList)
            {
                retList.Add(new Point(pt.X, pt.Y, pt.Z));
            }
            return retList;
        }
    }
}
